<?php
// +----------------------------------------------------------------------
// | NewThink [ Think More,Think Better! ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2018 http://www.newthink.cc All rights reserved.
// +----------------------------------------------------------------------
// | 版权所有：山西创泰网络科技有限公司
// +----------------------------------------------------------------------
// | Author: JiYun Date:2019-02-28 Time:16:42
// +----------------------------------------------------------------------

namespace app\common\Service\airquality;

use app\common\service\BaseService;
use app\common\model\airquality\AirQualityStationAqiRealtimeDayModel as StationAqiRealtimeDayModel;
use app\common\service\CommonService;
use think\Db;
use think\facade\Config;

/**
 * Class AirQualityStationAqiRealtimeDay
 * @package app\index\Service\airquality
 */
class AirQualityStationAqiRealtimeDayService extends BaseService
{
    /**
     * AirQualityStationAqiRealtimeDay constructor.
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * 获取7日数据
     * @author JiYun On 2019/03/01
     * @param array $param
     * @return array
     * @throws \Exception
     */
    public function get7DayRealtimeList($param = [])
    {
        $stationAqiRealtimeModel = new StationAqiRealtimeDayModel();

        try {
            $list = $stationAqiRealtimeModel->get7DayRealtimeList($param);
        } catch (\Exception $e) {
            throw $e;
        }

        return $list;
    }

    /**
     * 气象分析左侧表格数据
     * @author yy by 2019/5/7
     * @param array $param
     * @return mixed
     * @throws \MongoDB\Driver\Exception\Exception
     */
    public function getTable($param = [])
    {
        $commonService = new CommonService();
        #判断日期类型 只有年月区别
        if ($param['date_type'] == 'year') {
            $norm = '%Y';
        } elseif ($param['date_type'] == 'month') {
            $norm = '%Y-%m';
        } else {
            $norm = '%Y-%m-%d'; // TODO 处理日类型
        }
        # 查询区间相差天数
        if ($param['date_type'] == 'year') {
            $start = $param['start_time'] . '-01-01';
            $end   = $param['end_time'] . '-12-31';
        } elseif ($param['date_type'] == 'month') {
            $start          = $param['start_time'] . '-01';
            $end_first_day  = $param['end_time'] . '-01';//结束月的第一天
            $end_next_month = date('Y-m-d', strtotime("$end_first_day +1month"));//结束月的下一个月第一天
            $end            = date('Y-m-d', strtotime("$end_next_month -1day"));
        } else {
            $start = $param['start_time'];
            $end   = $param['end_time'];
        }
        $days = $this->diffDays($start, $end);
//        unset($param['date_type']);
        # 默认不同空气质量等级下的天数为'-'
        $level_data = [
            ['aqi_level' => '优', 'level_day' => '-'],
            ['aqi_level' => '良', 'level_day' => '-'],
            ['aqi_level' => '轻度', 'level_day' => '-'],
            ['aqi_level' => '中度', 'level_day' => '-'],
            ['aqi_level' => '重度', 'level_day' => '-'],
            ['aqi_level' => '严重', 'level_day' => '-'],
        ];
        # 查询不同空气质量等级下的天数
        $level_data_arr = Db::query("select count(id) as level_day,aqi_level
                            from air_quality_station_aqi_realtime_day
                            where region_id = ? and station_id = ? and DATE_FORMAT(publish_time, '$norm') between ? and ?
                            group by aqi_level", [$param['region_id'], $param['station_id'], $param['start_time'], $param['end_time']]);
        foreach ($level_data as $k11 => &$v11) {
            foreach ($level_data_arr as $k22 => $v22) {
                if ($v22['aqi_level'] == $v11['aqi_level']) {
                    $v11['level_day'] = $v22['level_day'];
                }
            }
        }
        # 查询每个空气质量等级下的日期，和mongodb数据表air_quality_pollutant_station_forecast_day日期publish_time关联
        $six_level_date       = Db::query("select DATE_FORMAT(publish_time, '%Y-%m-%d') as publish_time,aqi
                                            from air_quality_station_aqi_realtime_day 
                                            where region_id = ? and station_id = ? and DATE_FORMAT(publish_time, '$norm') between ? and ?
                                            ", [$param['region_id'], $param['station_id'], $param['start_time'], $param['end_time']]);
        $serious_level_date   = [];//严重
        $bad_level_date       = [];//重度
        $moderate_level_date  = [];//中度
        $mild_level_date      = [];//轻度
        $good_level_date      = [];//良
        $excellent_level_date = [];//优
        foreach ($six_level_date as $k => $v) {
            switch ($v['aqi']) {
                case $v['aqi'] > 300:
                    $serious_level_date[] = $v['publish_time'];
                    break;
                case $v['aqi'] > 200:
                    $bad_level_date[] = $v['publish_time'];
                    break;
                case $v['aqi'] > 150:
                    $moderate_level_date[] = $v['publish_time'];
                    break;
                case $v['aqi'] > 100:
                    $mild_level_date[] = $v['publish_time'];
                    break;
                case $v['aqi'] > 50:
                    $good_level_date[] = $v['publish_time'];
                    break;
                case $v['aqi'] > 0:
                    $excellent_level_date[] = $v['publish_time'];
                    break;
            }
        }
        $arr_level_date = ['serious'   => $serious_level_date,
                           'bad'       => $bad_level_date,
                           'moderate'  => $moderate_level_date,
                           'mild'      => $mild_level_date,
                           'good'      => $good_level_date,
                           'excellent' => $excellent_level_date];
        # 六参天数
        $six_param_data = Db::query("select count(id) as pollution_day, aqi_level, name
                              from air_quality_station_primary_pollutant_realtime_day
                              where region_id = ? and station_id = ? and DATE_FORMAT(publish_time, '$norm') between ? and ?
                              group by aqi_level, name", [$param['region_id'], $param['station_id'], $param['start_time'], $param['end_time']]);
        $six_param_days = Db::query("select aqi_level, name, DATE_FORMAT(publish_time, '%Y-%m-%d') as date
                              from air_quality_station_primary_pollutant_realtime_day
                              where region_id = ? and station_id = ? and DATE_FORMAT(publish_time, '$norm') between ? and ?
                              ", [$param['region_id'], $param['station_id'], $param['start_time'], $param['end_time']]);
        $new            = [];
        if (count($six_param_days) > 0) {
            # 将O3 和 O3_8H 存在于同一天和 单天只存在O3_8H的情况统一处理为O3
            foreach ($six_param_days as $kp => $vp) {
                $new[$vp['aqi_level']][strtoupper($vp['name'])][] = $vp['date'];
            }
            foreach ($new as $kn => &$vn) {
                # 查询日期区间 O3 和 O3_8H 同时存在，但是日期不同(将差别日期补到O3中)
                if (isset($vn['O3']) && isset($vn['O3_8H'])) {
                    # 比较差集
                    $different     = array_values(array_diff($vn['O3_8H'], $vn['O3']));
                    $different_num = count($different);
                    if ($different_num > 0) {
                        for ($i = 0; $i < $different_num; $i++) {
                            $vn['O3'][] = $different[$i];
                        }
                    }
                }
                # 查询日期区间只存在O3_8H （将日期全部补到O3中）
                if (!isset($vn['O3']) && isset($vn['O3_8H'])) {
                    $o3_8h_num = count($vn['O3_8H']);
                    for ($m = 0; $m < $o3_8h_num; $m++) {
                        $vn['O3'][] = $vn['O3_8H'][$m];
                    }
                }
            }
            # 统计各等级下各首要污染物出现的天数
            foreach ($new as $ks => &$vs) {
                foreach ($vs as $km => &$vm) {
                    $vm = count($vm);
                }
            }
        }
        foreach ($level_data as $k1 => &$v1) {
            # 天数占比
            if ($v1['level_day'] === '-') {
                $v1['day_rate'] = '-';
            } else {
                $v1['day_rate'] = (round($v1['level_day'] / $days, 2) * 100) . '%';
            }
            # 为避免查询日期范围内六参缺少，故声明默认天数为0
            $v1['pm10_day'] = 0;
            $v1['pm25_day'] = 0;
            $v1['so2_day']  = 0;
            $v1['no2_day']  = 0;
            $v1['o3_day']   = 0;
            $v1['co_day']   = 0;
//            foreach ($six_param_data as $k2 => $v2) {
//                if ($v2['aqi_level'] == $v1['aqi_level']) {
//                    $v1[str_replace('.', '', strtolower($v2['name'])) . '_day'] = $v2['pollution_day'];
//                }
//            }
            foreach ($new as $k2 => $v2) {
                if ($k2 === $v1['aqi_level']) {
                    foreach ($v2 as $k3 => $v3) {
                        $v1[str_replace('.', '', strtolower($k3)) . '_day'] = $v3;
                    }
                }
            }
        }
        #各等级各首要污染物天数
        foreach ($level_data as $k3 => &$v3) {
            if ($v3['level_day'] == '-') {
                $v3['primary_pollutant'] = '-';
            } else {
                $v3['primary_pollutant'] = 'PM2.5(' . $v3['pm25_day'] . ')、PM10(' . $v3['pm10_day'] . ')、SO2(' . $v3['so2_day'] . ')、NO2(' . $v3['no2_day'] . ')、O3(' . $v3['o3_day'] . ')、CO(' . $v3['co_day'] . ')';
            }
            unset($v3['pm10_day'], $v3['pm25_day'], $v3['so2_day'], $v3['no2_day'], $v3['o3_day'], $v3['co_day']);
        }
        # 查询各个AQI等级下工业非工业的天数占比 mongodb 例如 贡献度平均的工业占比 = 工业的值总和/(工业sum+非工业sum)
        if ($param['date_type'] == 'month') {
            $param['start_time'] = $param['start_time'] . '-01';
            $current_first_day   = date('Y-m-01', time());//本月一号
            $current_last_day    = date('Y-m-d', strtotime("$current_first_day +1 month - 1day"));//本月最后一天
            $param['end_time']   = $param['start_time'] . '-01';
            $param['end_time']   = $current_last_day;

        } elseif ($param['date_type'] == 'year') {
            $param['start_time'] = $param['start_time'] . '-01-01';
            $param['end_time']   = $param['end_time'] . '-12-31';
        }
        # 工业各等级空气质量下的贡献度平均
        $param['contribute_pollutant_name'] = 'PM2.5';
        $is_industry_contribute             = $this->getIsIndustryContribute($param, $arr_level_date, 1);
        # 非工业各等级空气质量下的贡献度平均
        $no_industry_contribute = $this->getIsIndustryContribute($param, $arr_level_date, 0);

        foreach ($level_data as $k4 => &$v4) {
            switch ($v4['aqi_level']) {
                case '优':
                    $v4['rate_is_industry_day'] = $is_industry_contribute['excellent'] ? $commonService->contributionRound($is_industry_contribute['excellent']) . '%' : '-';
                    $v4['rate_no_industry_day'] = $no_industry_contribute['excellent'] ? $commonService->contributionRound($no_industry_contribute['excellent']) . '%' : '-';
                    break;
                case '良':
                    $v4['rate_is_industry_day'] = $is_industry_contribute['good'] ? $commonService->contributionRound($is_industry_contribute['good']) . '%' : '-';
                    $v4['rate_no_industry_day'] = $no_industry_contribute['good'] ? $commonService->contributionRound($no_industry_contribute['good']) . '%' : '-';
                    break;
                case '轻度':
                    $v4['rate_is_industry_day'] = $is_industry_contribute['mild'] ? $commonService->contributionRound($is_industry_contribute['mild']) . '%' : '-';
                    $v4['rate_no_industry_day'] = $no_industry_contribute['mild'] ? $commonService->contributionRound($no_industry_contribute['mild']) . '%' : '-';
                    break;
                case '中度':
                    $v4['rate_is_industry_day'] = $is_industry_contribute['moderate'] ? $commonService->contributionRound($is_industry_contribute['moderate']) . '%' : '-';
                    $v4['rate_no_industry_day'] = $no_industry_contribute['moderate'] ? $commonService->contributionRound($no_industry_contribute['moderate']) . '%' : '-';
                    break;
                case '重度':
                    $v4['rate_is_industry_day'] = $is_industry_contribute['bad'] ? $commonService->contributionRound($is_industry_contribute['bad']) . '%' : '-';
                    $v4['rate_no_industry_day'] = $no_industry_contribute['bad'] ? $commonService->contributionRound($no_industry_contribute['bad']) . '%' : '-';
                    break;
                case '严重':
                    $v4['rate_is_industry_day'] = $is_industry_contribute['serious'] ? $commonService->contributionRound($is_industry_contribute['serious']) . '%' : '-';
                    $v4['rate_no_industry_day'] = $no_industry_contribute['serious'] ? $commonService->contributionRound($no_industry_contribute['serious']) . '%' : '-';
                    break;
            }
        }
        return $level_data;
    }

    /**
     * 获取工业、非工业的贡献度平均
     * @author yy by 2019/5/27
     * @param array $param
     * @param $arr_level_date 各空气质量等级出现的日期
     * @param $isIndustry 工业或者非工业
     * @return array
     * @throws \MongoDB\Driver\Exception\Exception
     */
    public function getIsIndustryContribute($param = [], $arr_level_date, $isIndustry)
    {
        $commonService = new CommonService();
        # 判断是工业还是非工业
        if ($isIndustry) {
            $isIndustryId = $commonService->getIndustryLimitId();
            $table        = Config::get('contribution_table_name');
        } else {
            $isIndustryId = $commonService->getNoIndustryLimitId();
            $table        = 'air_quality_pollutant_non_industry_area_forecast_day';
        }
//        $companyIdArr = $commonService->getCompanyIdArr(0);
        $newTime      = $commonService->getMongoTime($param);
        $list         = [];
        # 获取工业下不同行业不同企业这段时间内的平均贡献值
        $mongodb_huanxin    = new \MongoDB\Driver\Manager(Config::get('mongodb_url'));
        $document           = [
            'aggregate'    => $table,
            'pipeline'     => [
                [
                    '$project' => [
                        'predict_time'        => 1,
                        'publish_time'        => 1,
                        'contribution_name'   => 1,
                        'industry_id'         => 1,
                        'station_id'          => 1,
                        'region_id'           => 1,
                        'contribution_value'  => 1, //贡献度
                        'contribution_degree' => 1, //贡献值
                        'difference'          => ['$eq' => ['$publish_time', '$predict_time']]
                    ],
                ],
                [
                    '$match' => [
                        'difference'        => true,
                        'industry_id'       => ['$in' => $isIndustryId],
//                        'region_id'         => (int)$param['region_id'],//非工业有四个地方的region_id不为53，但需要统计
                        'station_id'        => (int)$param['station_id'],
                        'contribution_name' => strtoupper($param['contribute_pollutant_name']),
                        'predict_time'      => [
                            '$gte' => $newTime['start_time'],
                            '$lte' => $newTime['end_time'],
                        ],
                    ]
                ],
            ],
            'allowDiskUse' => true,
        ];
        $command            = new \MongoDB\Driver\Command($document);
        $rows               = $mongodb_huanxin->executeCommand('huanxin', $command)->toArray();
        $contribution_trend = json_decode(json_encode($rows, 320), true);
        # 查出PM2.5溯源物在这个站点的时间区间浓度之和（20190620新算法）
        $param['pollutant_name'] = 'pm25';
        $concentration           = $commonService->getConcentration($param, $arr_level_date);
        $sum = array_sum(array_column($contribution_trend[0]['result'], 'contribution_degree'));
        $num                     = count($contribution_trend[0]['result']);
        $arr                     = [];
        if ($num > 0) {
            foreach ($contribution_trend[0]['result'] as $k => $v) {
                # PM2.5 不同空气质量等级下的 (工业下不同行业不同企业)时间区间内的贡献度
                foreach ($arr_level_date as $k5 => $v5) {
                    if (in_array(date("Y-m-d", strtotime($v['publish_time'])), $v5)) {
                       // 工业的贡献度 = 工业下企业贡献值的和 / 站点的小时浓度和
                        $arr[$k5][] = (isset($concentration[$k5]) && $concentration[$k5] > 0) ? $v['contribution_degree'] : '';//20190619算法
                    }
                }
            }
            # 计算（工业非工业）下的贡献值（20160619确认算法工业、行业、企业的贡献度均依据贡献值计算）
            foreach ($arr as $k1 => &$v1) {
                //$v1 = (isset($concentration[$k1]) && $concentration[$k1] > 0) ? (array_sum($v1) / $concentration[$k1]) / count($arr_level_date[$k1]) : '';
                $v1 = (isset($concentration[$k1]) && $concentration[$k1] > 0) ? (array_sum($v1) / $concentration[$k1]) : '';
            }
        }
        $list['serious']   = isset($arr['serious']) ? $arr['serious'] : '';
        $list['bad']       = isset($arr['bad']) ? $arr['bad'] : '';
        $list['moderate']  = isset($arr['moderate']) ? $arr['moderate'] : '';
        $list['mild']      = isset($arr['mild']) ? $arr['mild'] : '';
        $list['good']      = isset($arr['good']) ? $arr['good'] : '';
        $list['excellent'] = isset($arr['excellent']) ? $arr['excellent'] : '';
        return $list;
    }

    /**
     * 获取工业非工业的值总和
     * @author yy by 2019/4/17
     * @param $need 各空气质量等级的出现的日期集合
     * @param $all mongodb贡献度工业非工业的数据
     * @param $is_industry_ids 工业id集合
     * @return mixed
     */
    public function getContributeRate($need, $all, $is_industry_ids)
    {
        $need['contribute_sum']             = 0;
        $need['is_industry_contribute_sum'] = 0;
        $need['no_industry_contribute_sum'] = 0;
        foreach ($all as $k => $v) {
            if (in_array($v['publish_time'], $need)) {
                $need['contribute_sum'] += $v['contribution_value'];
                if (in_array($v['industry_id'], $is_industry_ids)) {
                    $need['is_industry_contribute_sum'] += $v['contribution_value'];
                } else {
                    $need['no_industry_contribute_sum'] += $v['contribution_value'];
                }
            }
        }
        return $need;
    }

    /**
     * 获取首要污染物占比 TODO
     * @author yy by 2019/4/3
     * @param array $param
     * @return array
     */
    public function getPrimaryPollutantRate($param = [])
    {
        #判断日期类型 只有年月区别
        if ($param['date_type'] == 'year') {
            $norm = '%Y';
        } else {
            $norm = '%Y-%m';
        }
        unset($param['date_type']);
        $six_param_data = Db::query("select count(id) as pollution_day,primary_pollutant_name
                            from air_quality_station_aqi_realtime_day
                            where station_id =:station_id and DATE_FORMAT(publish_time, '$norm') between :start_time and :end_time and aqi_level =:aqi_level
                            group by primary_pollutant_name", $param);
        #默认值(符合前台格式)
        $list = [['name' => 'PM10', 'value' => 0],
            ['name' => 'PM25', 'value' => 0],
            ['name' => 'SO2', 'value' => 0],
            ['name' => 'NO', 'value' => 0],
            ['name' => 'CO', 'value' => 0],
            ['name' => 'O3', 'value' => 0]];
        foreach ($six_param_data as $k => &$v) {
            $v['primary_pollutant_name'] = str_replace('.', '', $v['primary_pollutant_name']);
            foreach ($list as $k1 => &$v1) {
                if ($v1['name'] == $v['primary_pollutant_name']) {
                    $v1['value'] = $v['pollution_day'];
                }
            }
        }
        var_dump($list);
//        return $list;
    }

    /**
     * 优良条件下的六参平均值 TODO
     * @author yy by 2019/4/3
     * @param array $param
     */
    public function getSixParamAverage($param = [])
    {
        #判断日期类型 只有年月区别
        if ($param['date_type'] == 'year') {
            $norm = '%Y';
        } else {
            $norm = '%Y-%m';
        }
        unset($param['date_type']);
        $six_param_average = Db::query("select avg(pm10) as pm10_average,sum(pm25) as pm25_average,avg(so2) as so2_average,avg(no2) as no2_average,avg(co) as co_average,avg(o3) as o3_average
                            from air_quality_station_aqi_realtime_day
                            where station_id =:station_id and DATE_FORMAT(publish_time, '$norm') between :start_time and :end_time and aqi_level =:aqi_level", $param);
        #默认值(符合前台格式)
//        $list = [['name' => 'PM10', 'value' => 0],
//            ['name' => 'PM25', 'value' => 0],
//            ['name' => 'SO2', 'value' => 0],
//            ['name' => 'NO', 'value' => 0],
//            ['name' => 'CO', 'value' => 0],
//            ['name' => 'O3', 'value' => 0]];
//        foreach ($six_param_data as $k => &$v) {
//            $v['primary_pollutant_name'] = str_replace('.', '', $v['primary_pollutant_name']);
//            foreach ($list as $k1 => &$v1) {
//                if ($v1['name'] == $v['primary_pollutant_name']) {
//                    $v1['value'] = $v['pollution_day'];
//                }
//            }
//        }
        var_dump($six_param_average);
//        return $list;
    }

    /**
     * 日期范围相差天数
     * @author yy by 2019/3/21
     * @param $start_time
     * @param $end_time
     * @return float
     */
    public function diffDays($start_time, $end_time)
    {
        $start = strtotime($start_time);
        $end   = strtotime($end_time);
        $days  = round(($end - $start) / 3600 / 24) + 1;
        return $days;
    }

}
